/**
 * 首页
 */
import React, { Component, useState, useEffect, useLayoutEffect, memo, useCallback , useMemo, useRef, useReducer, useContext} from "react";
import { Link } from "react-router-dom";
import Styles from "./index.less";
import Logo from "@/assets/logo.svg";
import HelloWorld from "@/components/HelloWorld";
import { render } from "less";

//初始化store的类型、初始化值、创建reducer
const ADD_COUNTER = 'ADD_COUNTER';

const initReducer = {
	count: 0
};

//正常的reducer编写
function reducer(state, action) {
	switch (action.type) {
		case ADD_COUNTER:
			return { ...state, count: state.count + 1 };
		default:
			return state;
	}
}

const MyContext = React.createContext({});


const usePrevious = (count) => {
  const ref = useRef()

  useEffect(() => {
    ref.current = count
  }, [count])

  return ref.current
}

const Blank = () => {
  //创建了一个叫count的变量，setCount方法可以改变这个变量
  const [count, setCount] = useState(1)
  const [ name ] = useState('子组件')
  const [show, setShow] = useState(false)

  const [ state, dispatch ] = useReducer(reducer, initReducer);

  // 在子组件不需要父组件的值和函数的情况下，只需要使用 memo 函数包裹子组件即可。
  // 如果有函数传递给子组件，使用 useCallback
  // 如果有值传递给子组件，使用 useMemo
  // useEffect、useMemo、useCallback 都是自带闭包的。也就是说，每一次组件的渲染，其都会捕获当前组件函数上下文中的状态(state, props)，所以每一次这三种hooks的执行，反映的也都是当前的状态，你无法使用它们来捕获上一次的状态。对于这种情况，我们应该使用 ref 来访问。

  // 例子 获取上一次的count值
  const previous = usePrevious(count)

  // useMemo() 细粒度性能优化  只有当count发生改变时候才会出发渲染逻辑 相当于vue3的computed
  const doubleCount = useMemo(() => count * 2, [count])

  // useCallback的用法其实和useMemo是一样的，但是他们唯一的区别是，useCallback是缓存了函数。
  const handleChange = useCallback((num) => {
    console.log(num)
    setCount(count + num)
  }, [count])

  // useRef用于获取dom元素
  const input = useRef(null)
  const handleInput = () => {
    console.log(input.current)
  }

  return (
    <div>
      <button onClick={ () => handleChange(1)}>累加</button>
      <p ref={input} onClick={ () => handleInput() }>上一次的count值：{ previous }</p>
      数据双向绑定：
      <input value={count} onChange={e => setCount(e.target.value)}/>
      <p>reducer {state.count}</p>
      <p onClick={() => dispatch({ type: ADD_COUNTER, count: 17})}>button 改变reducer</p>
      <MyContext.Provider value={{ count, name }}>
        <Child2 />
      </MyContext.Provider>
      <Child count={ count } name={ name } doubleCount={doubleCount} show={ show } handleChange={ handleChange } />
    </div>
  )
}

const Child = memo((props) => {


  // useEffect在浏览器渲染完成后执行
  // 这样写可以代替以前的componentDidMount，第二个参数为空数组，表示该useEffect只执行一次
  useEffect(() => {
    console.log('我被创建了')
  }, [])

  // props.count改变触发
  useEffect(() => {
    console.log('我是count')
  }, [props.count])

  // props.name改变触发
  useEffect(() => {
    console.log('我是name')
  }, [props.name])

  // 这样写可以代替以前的componentWillUnMount
  useEffect(() => {
    return () => {
      console.log('我被销毁了')
    }
  })

  // useLayoutEffect在浏览器渲染前执行
  // useLayoutEffect 强制useEffect的执行为同步，并且先执行useLayoutEffect内部的函数
  // 这个是用在处理DOM的时候,当你的useEffect里面的操作需要处理DOM,并且会改变页面的样式,就需要用这个,否则可能会出现出现闪屏问题
  // 例如 可能需要在页面初始化的时候立即修改位置和颜色（造成页面闪烁的情况下）

  useLayoutEffect(() => {
    console.log('我是useLayoutEffect')
    return () => {
      console.log('useLayoutEffect被销毁了')
    };
  }, [])

  return (
    <div>
      <p onClick={() => props.handleChange(1)}>{ props.count }</p>
      <p>{ props.doubleCount }</p>
      <p>{ props.show }</p>
      <p>{ props.name }</p>
    </div>
  )
})

const Child2 = () => {
  const { count, name } = useContext(MyContext)
  return (
    <div>
      <p>Child2</p>
      <p>{ count }</p>
      <p>{ name }</p>
    </div>
  )
}

export default Blank
